#include<iostream>
#include <array>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cstring>
using namespace std;
//信号产生的五种方式
//1、键盘产生
//2、调用系统命令 kill raise 等命令
//3、硬件异常产生信号
//4、软件发出信号
static void Uage(const string &proc)
{
    cout<<"\nUage:"<<proc<<"pid sign0\n"<<endl;
}

void handler2(int num)
{
    std::cout<<"这里是自定义的信号2 "<<num<<std::endl;
    //exit(0);
}
void handler9(int num)
{
     std::cout<<"这里是自定义的信号9 "<<num<<std::endl;
}
int cnt=0;

void catchSig(int signo)
{
    //cout<<"捕捉到硬件异常错误"<<signo<<endl;
    cout<<"闹钟结束:"<<cnt <<"  pid:"<<getpid()<<endl;  
    //exit(1);
}

int main(int argc, char* argv[])
{

    // for(int signo = 1; signo <= 31; signo++)
    // {
    //     signal(signo, catchSig); //无论如何9好信号是无法被自定义捕捉的
    // }

    // //核心转储存
    // while(true)
    // {
    //     int a[10];
        
    //     a[10000]=100;   //数据越界访问不一定会发生段错误,虽然给你分配了10个空间的数组元素，但是对于整个函数开辟的空间而言，不止10个，而且数组是抽查，不是严格的检测，所以只要不是完全不是你自己的空间，就有可能不会报错
    //     std::array<int,2> ab={1,2};
    //     ab[1000]=10;  //只有array是严格的检查，如果越界就报错

    // }

    // 4. 软件条件 -- "闹钟"其实就是用软件实现的
    // IO其实很慢
    // 统计1S左右，我们的计算机能够将数据累计多少次!
    signal(SIGALRM, catchSig);  //在闹钟响应之后，闹钟就停止工作了，就不会在接着打印了，出了在闹钟内部再次设置alarm(1),可以再次调度闹钟
    alarm(1);
    while(true)
    {
        cnt++;
    }




    // //3、产生信号的方式：硬件异常产生信号，一般都是CPU内的寄存器
    //这是操作系统自动调用的，跟用户关系不大
    // //信号的产生不一定非得用户显示的发送！

    // //除0错误
    // int a = 10;
    // // 如何证明？
    // // 受到信号，不一定会引起进程退出 -- 没有退出，有可能还会被调到
    // // -- CPU内部的寄存器只有一份，但是寄存器中的内容，属于当前进程的上下文！
    // // 你有没有能力或者动作修正这个问题呢？没有
    // // 当进程被来回切换的时候，就有无数次状态寄存器被保存和回复的过程
    // // 所以每一次恢复的时候，就让OS识别到了CPU内部的状态寄存器中的溢出标志位是1
    // // OS如何得知应该给当前进程发送8号信号的-- OS怎么知道我除0了呢？？，CPU会异常
    // a /= 0; // 为什么除0 会终止进程？当前进程会受到来自OS系统的信号(告知)，SIGFPE-> Floating point exception
    // signal(11, catchSig);

    //野指针的访问也会导致硬件异常
    // signal(11,catchSig);
    // while(true)
    // {
    //     cout<<"i am running..."<<endl;
    //     sleep(1);
    //     int* p =nullptr; 
    //     //OS怎么知道我野指针了呢？
    //     //为什么野指针会崩溃？因为操作系统会给当前进程发送指定的11号信号，段错误
    //     *p=100;
    // }

//     //2、系统向目标进程发送命令
//     // kill()可以向任意进程发送任意信号，跟bash下面的命令kill -x -pid是一个意思
//     // raise() 给自己 发送 任意信号kill(getpid(), 任意信号)
//     // abort() 给自己 发送 指定的信号SIGABRT, kill(getpid(), SIGABRT)
//     // 关于信号处理的行为的理解：有很多的情况，进程收到大部分的信号，默认处理动作都是终止进程
//     // 信号的意义：信号的不同，代表不同的事件，但是对事件发生之后的处理动作可以一样！
   
//    //使用abort函数以及raise系统调用
//     int cnt = 0;
//     while(cnt <= 10)
//     {
//         printf("cnt: %d, pid: %d\n", cnt++, getpid());
//         sleep(1);
//         //if(cnt >= 5) abort(); // kill(getpid(), signo)
//         if(cnt >= 5) raise(9); // kill(getpid(), signo)
//     }
    // //模仿kill命令，用一个程序去中止另外一个程序
    // if(argc!=3)
    // {
    //     Uage(argv[0]);
    //     exit(1);
    // }
    // pid_t pid = atoi(argv[1]);   //./mysignal pid 9 2 .....
    // int signo = atoi(argv[2]);
    // int n=kill(pid,signo); 
    // if(n!=0)
    // {
    //     perror("kill");
    // }


    // //1、硬件产生信号，中止进程
    // //crtl+c   crtl+反斜杠
    // while(true)
    // {
    //     cout<<"我正在执行...."<<getpid()<<endl;
    //     sleep(1);
    // }



    // 0、调用signal函数，重写系统的信号
    // //这里是signal函数的调用，并不是handler的调用
    // //仅仅是设置了对2好信号的捕捉方法，并不代表该方法被调用了
    // //一般这个方法不会被执行，除非收到对应的信号
    // signal(2,handler2);
    // signal(9,handler9);  //不能被自定义
    // while(true)
    // {
    //     std::cout<<"我是一个进程: "<<getpid()<<std::endl;
    //     sleep(1);
    // }
    return 0;
}